﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Shapes;
using WinRTXamlToolkit.Composition;

namespace SignatureBoxControl
{
  public class SignatureBox : Canvas
  {
    Point previousPosition = default(Point);
    List<List<Point>> allPoints = new List<List<Point>>();
    bool pressed = false;

    #region Properties

    public bool IncludeBackground
    {
      get { return (bool)GetValue(IncludeBackgroundProperty); }
      set { SetValue(IncludeBackgroundProperty, value); }
    }

    // Using a DependencyProperty as the backing store for IncludeBackground.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IncludeBackgroundProperty =
        DependencyProperty.Register("IncludeBackground", typeof(bool), typeof(SignatureBox), new PropertyMetadata(false));


    public double InkThickness
    {
      get { return (double)GetValue(InkThicknessProperty); }
      set { SetValue(InkThicknessProperty, value); }
    }

    // Using a DependencyProperty as the backing store for InkThickness.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty InkThicknessProperty =
        DependencyProperty.Register("InkThickness", typeof(double), typeof(SignatureBox), new PropertyMetadata(2));


    public Brush InkColor
    {
      get { return (Brush)GetValue(InkColorProperty); }
      set { SetValue(InkColorProperty, value); }
    }

    // Using a DependencyProperty as the backing store for InkColor.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty InkColorProperty =
        DependencyProperty.Register("InkColor", typeof(Brush), typeof(SignatureBox), new PropertyMetadata(new SolidColorBrush(Colors.DarkBlue)));

    #endregion

    public SignatureBox()
    {
      this.PointerExited += SignatureBox_PointerExited;
      this.PointerMoved += SignatureBox_PointerMoved;
      this.PointerPressed += SignatureBox_PointerPressed;
      this.PointerReleased += SignatureBox_PointerReleased;
      this.Loaded += SignatureBox_Loaded;
    }

    /// <summary>
    /// Fires when SignatureBox has been loaded.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void SignatureBox_Loaded(object sender, RoutedEventArgs e)
    {
      var background = base.Background ?? new SolidColorBrush(Colors.White);
      this.Background = background;

      // If IncludeBackground is set to true then a rectangle will be added that will be
      // the same size as the signature box. 
      if (this.IncludeBackground)
      {
        Rectangle rectangle = new Rectangle();
        rectangle.Fill = background;
        rectangle.Width = base.Width;
        rectangle.Height = base.Height;

        this.Children.Add(rectangle);
      }
    }

    /// <summary>
    /// Canvas is being touched for the first time
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void SignatureBox_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
    {
      previousPosition = e.GetCurrentPoint(this).Position;
      allPoints.Add(new List<Point>());
      allPoints.Last().Add(previousPosition);

      pressed = true;
    }

    /// <summary>
    /// Pointer is moved over the canvas
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void SignatureBox_PointerMoved(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
    {
      if (!pressed) return;

      var positions = e.GetIntermediatePoints(this).Select(ppt => ppt.Position);

      foreach (Point pt in positions)
      {
        this.Children.Add(
          new Line()
          {
            X1 = previousPosition.X,
            Y1 = previousPosition.Y,
            X2 = pt.X,
            Y2 = pt.Y,
            Stroke = this.InkColor,
            StrokeThickness = this.InkThickness
          }
        );
        previousPosition = pt;
      }
      allPoints.Last().AddRange(positions);
    }

    /// <summary>
    /// Pointer was removed from canvas
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void SignatureBox_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
    {
      if (pressed)
        pressed = false;
    }

    /// <summary>
    /// Pointer is outside canvas
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void SignatureBox_PointerExited(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
    {
      if (pressed)
        pressed = false;
    }

    /// <summary>
    /// Clear signature from all ink
    /// </summary>
    public void Clear()
    {
      var lines = new List<Line>();

      foreach (var child in this.Children)
      {
        if (child.GetType() == typeof(Line))
        {
          lines.Add(child as Line);
        }
      }

      foreach (var line in lines)
        this.Children.Remove(line);
    }

    /// <summary>
    /// Return contents of current canvas as an image
    /// </summary>
    /// <returns></returns>
    //public async Task<WriteableBitmap> GetSignatureAsync()
    //{
    //  return await WriteableBitmapRenderExtensions.Render(this);
    //}

    /// <summary>
    /// Return contents of current canvas as a PNG stream
    /// </summary>
    /// <returns></returns>
    public async Task<MemoryStream> GetSignaturePngStreamAsync()
    {
      return await WriteableBitmapRenderExtensions.RenderToPngStream(this);
    }
  }
}
